package fr.ensai.lignededix.bd;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import fr.ensai.lignededix.exceptions.FonctionalException;
import fr.ensai.lignededix.metier.jeton.Diable;
import fr.ensai.lignededix.metier.jeton.Joker;
import fr.ensai.lignededix.metier.jeton.Multi;
import fr.ensai.lignededix.metier.jeton.Simple;
import fr.ensai.lignededix.metier.joueur.IA0;
import fr.ensai.lignededix.metier.joueur.IA1;
import fr.ensai.lignededix.metier.joueur.IA2;
import fr.ensai.lignededix.metier.joueur.Joueur;

import fr.ensai.lignededix.metier.partie.Case;
import fr.ensai.lignededix.metier.partie.Coup;
import fr.ensai.lignededix.metier.partie.Partie;

public class PartieDAO extends DAO<Partie>{


	@Override
	public int create(Partie obj) throws FonctionalException {

		int idCoup=0;

		try {
			Statement instruction = connect.createStatement();
			ResultSet resultat= instruction.executeQuery("SELECT seqPartie.nextval from dual");
			resultat.next();
			idCoup=resultat.getInt(1);


			java.sql.Date dateSql = new java.sql.Date(obj.getDateDebut().getTime()) ;


			instruction.executeUpdate("INSERT INTO PARTIE (idPartie, idUtilisateur1, idUtilisateur2,score1,score2,tailleGrille,dateDebut,dateFin) VALUES " +
					"("+idCoup+","+obj.getLesJoueurs().get(0).getNumUtilisateur()+"," +
					""+obj.getLesJoueurs().get(1).getNumUtilisateur()+","+obj.getScoreJoueurUn()+"," +
					""+obj.getScoreJoueurDeux()+","+obj.getTailleGrille()+",TO_DATE('"+dateSql+"','YYYY-MM-DD'),"+obj.getDateFin()+")");

			//	Fermeture de l'instruction
			instruction.close();

		}
		catch (SQLException e){ 

			throw new FonctionalException("La partie n'a pa pu être sauvegardée.");
		}
		return idCoup;
	}

	@Override
	public void delete(Partie obj) throws FonctionalException {
		try {
			Statement instruction = connect.createStatement();
			instruction.executeUpdate("DELETE FROM PARTIE WHERE idPartie="+obj.getNumPartie()+"");

		}catch(SQLException e){
			throw new FonctionalException("La sauvegarde de la partie a echoué.");
		}
	}

	@Override

	public Partie find(int id) throws FonctionalException {

		Partie p1=null;
		List<Joueur> listJoueur=new ArrayList<Joueur>();
		List<Coup> listCoup=new ArrayList<Coup>();

		try {

			Statement instruction = connect.createStatement();
			Statement instruction2 = connect.createStatement();
			Statement instruction3 = connect.createStatement();

			ResultSet resultat1=instruction.executeQuery("SELECT login,motDePasse FROM PARTIE,UTILISATEUR where UTILISATEUR.idUtilisateur=PARTIE.idUtilisateur1" +
					" and idPartie="+id+"");
			resultat1.next();
			Joueur j1=new Joueur(1,Joueur.NOIR, resultat1.getString("login"),resultat1.getString("motDePasse"));//1

			ResultSet resultat2=instruction.executeQuery("SELECT login,motDePasse FROM PARTIE,UTILISATEUR where UTILISATEUR.idUtilisateur=PARTIE.idUtilisateur2" +
					" and idPartie="+id+"");
			resultat2.next();
			Joueur j2=null;
			if (resultat2.getString("login").equals("IA0")){
				j2=new IA0(2,Joueur.BLANC, resultat2.getString("login"),resultat2.getString("motDePasse"));//2
			}
			else{
				if(resultat2.getString("login").equals("IA1")){
					j2=new IA1(2,Joueur.BLANC, resultat2.getString("login"),resultat2.getString("motDePasse"));//2
				}
				else {
					if(resultat2.getString("login").equals("IA2")){
						j2=new IA2(2,Joueur.BLANC, resultat2.getString("login"),resultat2.getString("motDePasse"));//2
					}
					else{
						j2=new Joueur(2,Joueur.BLANC, resultat2.getString("login"),resultat2.getString("motDePasse"));//2
					}
				}
			}


			listJoueur.add(j1);
			listJoueur.add(j2);

			ResultSet resultat3=instruction.executeQuery("SELECT * FROM PARTIE,COUP,JETON " +
					"where Coup.idPartie=PARTIE.idPartie and Partie.idPartie="+id+" and" +
					" COUP.idJeton=JETON.idJeton ORDER BY idCoup"); 


			int idPartie=0;
			int score1=0;
			int score2=0;
			int taille=0;
			Date dateDeb=null;
			Date dateFin=null;

			while (resultat3.next()) {

				int idCoup=resultat3.getInt("idCoup");
				String couleur=resultat3.getString("couleur");
				int valeur=resultat3.getInt("valeur");
				String typeJeton=resultat3.getString("typeJeton");

				Case caseDepart;
				Case caseArrivee;

				ResultSet resultat4=instruction2.executeQuery("SELECT xCase,yCase FROM CASES,COUP WHERE CASES.idCase=COUP.idCaseDepart and idCoup="+idCoup+"");
				resultat4.next();

				ResultSet resultat5=instruction3.executeQuery("SELECT xCase,yCase FROM CASES,COUP WHERE CASES.idCase=COUP.idCaseArrivee and idCoup="+idCoup+"");
				resultat5.next();

				switch (Integer.valueOf(typeJeton)) {


				case 0://Jeton Simple

					Simple jetonSimple=new Simple(couleur, valeur);

					caseDepart=new Case(resultat4.getInt("xCase"), resultat4.getInt("yCase"));
					caseArrivee=null;
					listCoup.add(new Coup(jetonSimple , caseDepart, caseArrivee, id));

					break;

				case 1: //Jeton Multi

					Multi jetonMulti=new Multi(resultat3.getString("couleur"), resultat3.getInt("valeur"));

					caseDepart=new Case(resultat4.getInt("xCase"), resultat4.getInt("yCase"));
					caseArrivee=null;

					listCoup.add(new Coup(jetonMulti , caseDepart, caseArrivee, id));

					break;

				case 2://Jeton Joker

					Joker jetonJoker=new Joker(resultat3.getString("couleur"), resultat3.getInt("valeur"));

					caseDepart=new Case(resultat4.getInt("xCase"), resultat4.getInt("yCase"));
					caseArrivee=new Case(resultat5.getInt("xCase"), resultat5.getInt("yCase"));

					listCoup.add(new Coup(jetonJoker , caseDepart, caseArrivee, id));

					break;

				case 3://Jeton Diable

					Diable jetonDiable=new Diable(resultat3.getString("couleur"), resultat3.getInt("valeur"));

					caseDepart=new Case(resultat4.getInt("xCase"), resultat4.getInt("yCase"));
					caseArrivee=new Case(resultat5.getInt("xCase"), resultat5.getInt("yCase"));

					listCoup.add(new Coup(jetonDiable , caseDepart, caseArrivee, id));

					break;


				default:
					break;
				}

				idPartie=resultat3.getInt("idPartie");
				score1=resultat3.getInt("score1");
				score2=resultat3.getInt("score2");
				taille=resultat3.getInt("tailleGrille");
				dateDeb=resultat3.getDate("dateDebut");
				dateFin=resultat3.getDate("dateFin");


			}


			p1=new Partie(idPartie,score1,score2,
					taille,dateDeb,dateFin,listJoueur,listCoup);


			//Fermeture des instructions
			instruction.close();
			instruction2.close();
			instruction3.close();

		}
		catch (SQLException e){ 
			throw new FonctionalException("La partie n'a pa pu être sauvegardée.");
		}

		return p1;

	}


	public List<Partie> getAll(int idUtilisateur1, int idUtilisateur2) throws FonctionalException{

		List<Partie> listeParties = new ArrayList<Partie>();

		try {

			Statement instruction = connect.createStatement();
			Statement instruction2 = connect.createStatement();

			ResultSet resultat = instruction.executeQuery("SELECT * FROM (select * from Partie WHERE idUtilisateur1="+idUtilisateur1+" and dateFin is null and idUtilisateur2="+idUtilisateur2+"" +
					" UNION select * from partie WHERE idUtilisateur1="+idUtilisateur2+" and dateFin is null and idUtilisateur2="+idUtilisateur1+") order by idPartie");


			while (resultat.next()) {

				int numPartie = resultat.getInt("idPartie");

				List<Joueur> lesJoueurs = new ArrayList<Joueur>();

				int numJoueur1 = resultat.getInt("idUtilisateur1");

				int numJoueur2 = resultat.getInt("idUtilisateur2");

				ResultSet resultat1=instruction2.executeQuery("SELECT login,motDePasse FROM PARTIE,UTILISATEUR where UTILISATEUR.idUtilisateur=PARTIE.idUtilisateur1" +

						" and idPartie="+numPartie+"");
				resultat1.next();

				Joueur j1=new Joueur(numJoueur1,null, resultat1.getString("login"),"");//1

				ResultSet resultat2=instruction2.executeQuery("SELECT login,motDePasse FROM PARTIE,UTILISATEUR where UTILISATEUR.idUtilisateur=PARTIE.idUtilisateur2" +

						" and idPartie="+numPartie+"");
				resultat2.next();

				Joueur j2=new Joueur(numJoueur2,null, resultat2.getString("login"),"");//2

				lesJoueurs.add(j1);
				lesJoueurs.add(j2);

				Partie p = new Partie(resultat.getInt("idPartie"),resultat.getInt("score1"),resultat.getInt("score2"),resultat.getInt("tailleGrille"),resultat.getDate("dateDebut"),resultat.getDate("dateFin"),lesJoueurs,null);

				listeParties.add(p);			

			}

		} catch (SQLException e) {

			throw new FonctionalException("L'obtention de la liste des parties inachevées a échoué.");

		}
		return listeParties;

	}


	@Override
	public void updateDateFin(Partie obj) throws FonctionalException {

		int numPartie=obj.getNumPartie();

		try {

			Statement instruction = connect.createStatement();

			java.sql.Date dateSql2 = new java.sql.Date(obj.getDateFin().getTime()) ;
			instruction.executeUpdate("UPDATE PARTIE SET dateFin=TO_DATE('"+dateSql2+"','YYYY-MM-DD') where idPartie="+numPartie+"");
		}
		catch(SQLException e){
			throw new FonctionalException("Une erreur est survenue dans l'enregistrement de la date de fin de la partie.");
		}
	}



	@Override
	public void updateScore(Partie partieInterrompueOuFinie) throws FonctionalException {

		try {

			Statement instruction = connect.createStatement();

			instruction.executeUpdate("UPDATE PARTIE SET score1="+ partieInterrompueOuFinie.getScoreJoueurUn() +
					" where idPartie="+partieInterrompueOuFinie.getNumPartie()+"");
			instruction.executeUpdate("UPDATE PARTIE SET score2="+ partieInterrompueOuFinie.getScoreJoueurDeux() +
					" where idPartie="+partieInterrompueOuFinie.getNumPartie()+"");

		}
		catch(SQLException e){
			throw new FonctionalException("Une erreur est survenue dans l'enregistrement du score du joueur.");
		}
	}


	@Override
	public Partie update(Partie obj) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean isPseudoValide(String pseudo) {
		throw new UnsupportedOperationException();
	}

	@Override
	public int authentifier(String pseudo, String mdp) {
		throw new UnsupportedOperationException();
	}

	@Override
	public void executerRequete(String ligne) {
		throw new UnsupportedOperationException();

	}

	@Override
	public String calculerDesStatistiques(Partie obj) throws FonctionalException {
		throw new UnsupportedOperationException();
	}

	@Override
	public void sinscrireSurListeAttente(Partie obj)
			throws FonctionalException {
		throw new UnsupportedOperationException();

	}

	@Override
	public List<Partie> obtenirListeAttente(Partie obj)
			throws FonctionalException {
		throw new UnsupportedOperationException();

	}

	@Override
	public void desinscrireListeAttente(Partie obj)
			throws FonctionalException {
		throw new UnsupportedOperationException();
	}


	//Les Constructeurs

	public PartieDAO(Connection connect) {
		this.connect=connect;

	}




}
